﻿using Sustainalytics.Claims;
using Sustainalytics.Entities;
using Sustainalytics.ScreeningTool.BL;
using Sustainalytics.ScreeningTool.BL.Exceptions;
using Sustainalytics.ScreeningTool.Service.Utility;
using Sustainalytics.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Cors;

namespace Sustainalytics.ScreeningTool.Service
{
    [EnableCors(origins: "*", headers: "*", methods: "*")]
    //[AutoInvalidateCacheOutput]
    [RoutePrefix("api/v1/criterialevel1/{criteriaLevel1Id}/criterialevel2/{criteriaLevel2Id}/criterialevel3/{criteriaLevel3Id}/templatecriteria")]
    public class TemplateCriteriaController : ApiController, ITemplateCriteriaController
    {
        private readonly ICompanyScreening _companyScreening;
        private readonly IClaimsChecker _claimsChecker;

        public TemplateCriteriaController(
            ICompanyScreening companyScreening, 
            IClaimsChecker claimsChecker)
        {
            _companyScreening = companyScreening;
            _claimsChecker = claimsChecker;
        }

        //[CacheOutput(ServerTimeSpan = 100, ClientTimeSpan = 0, NoCache = true, MustRevalidate = true, Private = true)]
        [Route("")]
        public HttpResponseMessage Get(Guid? criteriaLevel1Id, Guid? criteriaLevel2Id, Guid? criteriaLevel3Id, [FromUri]ListOptions options, bool returnAllBaseCriteria = false)
        {
            try
            {
                List<BaseCriteria> baseCriteriaList = null;
                List<object> convertedCriteria = new List<object>();

                //return all TemplateCriteria (the datasource of the search criteria textbox)
                if (returnAllBaseCriteria)
                {
                    List<TemplateCriteria> templateCriteriaList = _companyScreening.ListTemplateCriteria().OrderBy(tc => (int)tc.CriteriaType).ToList();

                    templateCriteriaList.ForEach(tc =>
                    {
                        CriteriaLevel3 cl3 = _companyScreening.GetCriteriaLevelThree(tc.CriteriaLevel3Id);
                        // in case there is a TemplateCriteria having a non-existing CriteriaLevel3Id, send string.Empty
                        string piString = string.Empty;
                        string globalCompact = string.Empty;
                        if (tc.CriteriaType == CriteriaTypeEnum.CriteriaType4)
                        {
                            var symbol = tc.CriteriaEntityField.Split(' ').FirstOrDefault();
                            if (symbol != null)
                                piString = symbol;
                        }

                        if (tc.CriteriaType == CriteriaTypeEnum.CriteriaType7)
                        {
                            globalCompact = tc.Name;
                        }
                        if (tc.CriteriaType == CriteriaTypeEnum.CriteriaType3)
                        {
                            convertedCriteria.Add(TemplateCriteriaDto.CreateWithNameIdTypeIsEnabled(tc,
                                               ValidateCriteriaType3(tc),
                                               cl3 != null ? cl3.Name : string.Empty));
                        }
                        else
                        {
                            var criteriaLevel2 = _companyScreening.GetCriteriaLevelTwo(tc.CriteriaLevel2Id);
                            var isValid = ValidateCriteria(criteriaLevel2, piString, globalCompact);
                            var templateDto = TemplateCriteriaDto.CreateWithNameIdTypeIsEnabled(tc, isValid, cl3 != null ? cl3.Name : string.Empty);

                            if (criteriaLevel2.ShortName != "RiskRatings")
                            {
                                convertedCriteria.Add(templateDto);
                            }
                            else if (criteriaLevel2.ShortName == "RiskRatings" && isValid)
                            {
                                convertedCriteria.Add(templateDto);
                            }
                        }
                    });

                    return Request.CreateResponse(HttpStatusCode.OK, convertedCriteria);
                }

                //get TemplateCriteria for CriteriaLevel3Id
                if (criteriaLevel3Id != null)
                {
                    List<TemplateCriteria> templateCriteriaForLevel3 = _companyScreening.ListTemplateCriteriaByLevel3Id(criteriaLevel3Id);
                    List<TemplateCriteriaDto> templateCriteriaDto = new List<TemplateCriteriaDto>();

                    foreach (var item in templateCriteriaForLevel3)
                    {
                        if (item.CriteriaType == CriteriaTypeEnum.CriteriaType5)
                        {
                            var templateIndicatorNumber = item.Name.Split(' ').FirstOrDefault();
                            var indicatorTemplate = _companyScreening.GetIndicatorTemplate(templateIndicatorNumber);

                            templateCriteriaDto.Add(TemplateCriteriaDto.CreateLessTemplateCriteria(item, indicatorTemplate));
                        }
                        else if (item.CriteriaType == CriteriaTypeEnum.CriteriaType17)
                        {
                            var templateIndicatorNumber = item.Name.Split(' ').FirstOrDefault();
                            var indicatorTemplate = _companyScreening.GetGovernanceIndicatorTemplate(templateIndicatorNumber);

                            templateCriteriaDto.Add(TemplateCriteriaDto.CreateLessTemplateCriteria(item, indicatorTemplate));
                        }
                        else if (item.CriteriaType == CriteriaTypeEnum.CriteriaType25)
                        {
                            CriteriaType25 indicatorTemplate = new CriteriaType25();
                            indicatorTemplate.AnswerCategories = _companyScreening.GetAnswerCategoryForRiskRating(item);
                            templateCriteriaDto.Add(TemplateCriteriaDto.CreateLessTemplateCriteria(item, indicatorTemplate));
                        }
                        else
                        {
                            templateCriteriaDto.Add(TemplateCriteriaDto.CreateLessTemplateCriteria(item, null));
                        }
                    }
                    return Request.CreateResponse(HttpStatusCode.OK, templateCriteriaDto);
                }

                //get baseCriteriaList for CriteriaLevel2Id (not all)
                baseCriteriaList = _companyScreening.ListBaseCriteria(criteriaLevel2Id);
                baseCriteriaList.ForEach(bc =>
                {
                    if (bc.CriteriaType != CriteriaTypeEnum.CriteriaType4)
                    {
                        var criteriaLevel2 = _companyScreening.GetCriteriaLevelTwo(bc.CriteriaLevel2Id);
                        convertedCriteria.Add(TemplateCriteriaDto.CreateWithNameIdTypeIsEnabled(bc, ValidateCriteria(criteriaLevel2, "")));
                    }
                });
                return Request.CreateResponse(HttpStatusCode.OK, convertedCriteria);
            }
            catch (AuthorizationException)
            {
                return Request.CreateResponse(HttpStatusCode.Unauthorized);
            }
            catch (Exception)
            {
                return Request.CreateResponse(HttpStatusCode.InternalServerError, new { Code = ErrorCodes.ScreeningTool_LoadingCriteriaTabs });
            }
        }

        private bool ValidateCriteria(CriteriaLevel2 criteriaLevel2, string piSymbol, string globalCompact = "")
        {
            if (criteriaLevel2 == null)
                return false;

            if (!string.IsNullOrWhiteSpace(piSymbol))
            {
                return _claimsChecker.ValidateCriteria(this, criteriaLevel2.ShortName, piSymbol);
            }

            if (!string.IsNullOrWhiteSpace(globalCompact))
                if (_claimsChecker.ValidateCriteria(this, "gccsnc", null) ||
                    _claimsChecker.ValidateCriteria(this, "gccswl", null))
                    return true;

            if (!_claimsChecker.ValidateCriteria(this, criteriaLevel2.ShortName, piSymbol))
            {
                var criteriaLevel1 = _companyScreening.GetCriteriaLevelOne(criteriaLevel2.CriteriaLevel1Id);
                if (criteriaLevel1 == null)
                    return false;

                if (!_claimsChecker.ValidateCriteria(this, criteriaLevel1.ShortName, piSymbol))
                    return false;
            }

            return true;
        }

        private bool ValidateCriteriaType3(TemplateCriteria templateCriteria)
        {
            if (templateCriteria.Name.ToLowerInvariant() == "sedol" || templateCriteria.Name.ToLowerInvariant() == "wkn" || templateCriteria.Name.ToLowerInvariant() == "valor")
            {
                var ret = _claimsChecker.ValidateCriteria(this, templateCriteria.Name.ToLowerInvariant(), null);
                return ret;
            }
            return true;
        }
    }
}
